package org.cosmocalc;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.ui.ApplicationFrame;

import org.jfree.chart.axis.NumberAxis;
import org.jfree.data.xy.XYDataset;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYSplineRenderer;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.urls.StandardXYURLGenerator;


public class CosmoGraph extends ApplicationFrame implements WindowListener, MouseListener {
	private static final long serialVersionUID = 752305200528829433L;
	private static final int numberOfPoints = 201;
	private static final double finalz = 8.0;
	private static final double startz = 0.0;
	
	public CosmoGraph (String s) {
		super(s);
	}
	
	private void drawData(double[] x, double[] y, int np, String xtitle, String ytitle) {
		double[][] dd = new double[2][np];
		int i;
		DefaultXYDataset data = new DefaultXYDataset();

	    for (i=0;i<np;i++) {
	    	dd[0][i] = x[i];
	    	dd[1][i] = y[i];
	    }
	    data.addSeries(1, dd);

		JFreeChart chart = createXYSplineChart(null, xtitle, ytitle, data, 
				PlotOrientation.VERTICAL, false, true, false);
		ChartPanel chartpanel = new ChartPanel(chart);
		setContentPane(chartpanel);
		
        addWindowListener(this);
        addMouseListener(this);
        
        this.setLocation(350,0);
        this.pack();
        this.setVisible(true);
        
		return;
	}

    /**
     * Creates a spline chart (based on an {@link XYDataset}) with default 
     * settings.
     *
     * @param title  the chart title (<code>null</code> permitted).
     * @param xAxisLabel  a label for the X-axis (<code>null</code> permitted).
     * @param yAxisLabel  a label for the Y-axis (<code>null</code> permitted).
     * @param dataset  the dataset for the chart (<code>null</code> permitted).
     * @param orientation  the plot orientation (horizontal or vertical) 
     *                     (<code>null</code> NOT permitted).
     * @param legend  a flag specifying whether or not a legend is required.
     * @param tooltips  configure chart to generate tool tips?
     * @param urls  configure chart to generate URLs?
     *
     * @return The chart.
     */
    public static JFreeChart createXYSplineChart(String title,
                                               String xAxisLabel,
                                               String yAxisLabel,
                                               XYDataset dataset,
                                               PlotOrientation orientation,
                                               boolean legend,
                                               boolean tooltips,
                                               boolean urls) {

        if (orientation == null) {
            throw new IllegalArgumentException("Null 'orientation' argument.");
        }
        NumberAxis xAxis = new NumberAxis(xAxisLabel);
        xAxis.setAutoRangeIncludesZero(false);
        NumberAxis yAxis = new NumberAxis(yAxisLabel);
        XYLineAndShapeRenderer renderer = new XYSplineRenderer();
        renderer.setBaseShapesVisible(false);
        XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
        plot.setOrientation(orientation);
        if (tooltips) {
            renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
        }
        if (urls) {
            renderer.setURLGenerator(new StandardXYURLGenerator());
        }

        JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT,
                plot, legend);

        return chart;

    }

	public void dlGraph(CosmoCalculator cosmoCalc) {
		double[] z  = new double[numberOfPoints];
		double[] dl = new double[numberOfPoints];
		double step;
		int i;
		for (i=0;i<numberOfPoints;i++){
			step  = (finalz - startz)/(1. * numberOfPoints - 1.);
			z [i] = step*i + startz;
			dl[i] = cosmoCalc.lumDist(z[i]);
		}
		this.drawData(z, dl, numberOfPoints, "Redshift", "Luminosity distance (Gpc)");
		return;
	}

	public void daGraph(CosmoCalculator cosmoCalc) {
		double[] z  = new double[numberOfPoints];
		double[] da = new double[numberOfPoints];
		double step;
		int i;
		for (i=0;i<numberOfPoints;i++){
			step  = (finalz - startz)/(1. * numberOfPoints - 1.);
			z [i] = step*i + startz;
			da[i] = cosmoCalc.angDist(z[i]);
		}
		this.drawData(z, da, numberOfPoints, "Redshift", "Angular distance (kpc per arcsec)");
		return;
	}

	public void ageGraph(CosmoCalculator cosmoCalc) {
		double[] z   = new double[numberOfPoints];
		double[] age = new double[numberOfPoints];
		double step;
		int i;
		for (i=0;i<numberOfPoints;i++){
			step  = (finalz - startz)/(1. * numberOfPoints - 1.);
			z [i] = step*i + startz;
			age[i] = cosmoCalc.time(z[i]);
		}
		this.drawData(z, age, numberOfPoints, "Redshift", "Time since Big Bang (Gyrs)");
		return;
	}

	public void lbGraph(CosmoCalculator cosmoCalc) {
		double[] z  = new double[numberOfPoints];
		double[] lb = new double[numberOfPoints];
		double step;
		int i;
		for (i=0;i<numberOfPoints;i++){
			step  = (finalz - startz)/(1. * numberOfPoints - 1.);
			z [i] = step*i + startz;
			lb[i] = cosmoCalc.lookbackTime(z[i]);
		}
		this.drawData(z, lb, numberOfPoints, "Redshift", "Lookback time (Gyrs)");
		return;
	}

	public void windowOpened(WindowEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void windowIconified(WindowEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void windowDeiconified(WindowEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void windowActivated(WindowEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void windowDeactivated(WindowEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void windowClosing(WindowEvent event) {
		Window theWindow = event.getWindow();
		theWindow.dispose();
	}

	public void windowClosed(WindowEvent event) {
		
	}

	public void mousePressed(MouseEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void mouseReleased(MouseEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void mouseEntered(MouseEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void mouseExited(MouseEvent event) {
		// TODO Auto-generated method stub
		
	}

	public void mouseClicked(MouseEvent event) {
	}

}
